home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / rmdir.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  5KB  |  219 lines

  1. /* rmdir - remove a directory        Author: Adri Koppes
  2.  
  3. /* (modified by Paul Polderman)
  4.  * (modified by Bjarne Steinsbo)    Fixed "rmdir ../anything"
  5.  *                    Modified style to standard Minix
  6.  *                    Added some comments.
  7.  */
  8.  
  9. #include <sys/types.h>
  10. #include <fcntl.h>
  11. #include <signal.h>
  12. #include <sys/stat.h>
  13. #include <sys/dir.h>
  14. #include <limits.h>
  15. #include <string.h>
  16.  
  17. int error = 0;
  18.  
  19. main(argc, argv)
  20. register int argc;
  21. register char **argv;
  22. {
  23.   if (argc < 2) {
  24.     prints("Usage: rmdir dir ...\n");
  25.     exit(1);
  26.   }
  27.   signal(SIGHUP, SIG_IGN);
  28.   signal(SIGINT, SIG_IGN);
  29.   signal(SIGQUIT, SIG_IGN);
  30.   signal(SIGTERM, SIG_IGN);
  31.   while (--argc) remove(*++argv);
  32.   if (error) exit(1);
  33. }
  34.  
  35.  
  36. remove(dirname)
  37. char *dirname;
  38. {
  39.   struct direct d;        /* buffer for reading directory */
  40.   struct stat s, cwd;        /* buffers for `stat' call */
  41.   int fd = 0;
  42.   int sl = 0;
  43.   int n;
  44.   char dots[PATH_MAX];        /* scratch buffer for dirname */
  45.   register char *p;
  46.  
  47.   /* Is the path name too long ? Check once and for all. */
  48.   if (strlen(dirname) > PATH_MAX - 3) {    /* Need to append `/..' */
  49.     stderr2("path name too long : ", dirname);
  50.     std_err("\n");
  51.     error++;
  52.     return;
  53.   }
  54.  
  55.   /* Does the file exist ? */
  56.   if (stat(dirname, &s)) {
  57.     stderr2(dirname, " doesn't exist\n");
  58.     error++;
  59.     return;
  60.   }
  61.  
  62.   /* Is it a directory ? */
  63.   if ((s.st_mode & S_IFMT) != S_IFDIR) {
  64.     stderr2(dirname, " not a directory\n");
  65.     error++;
  66.     return;
  67.   }
  68.  
  69.   /* If path ends in /., fix it (e.g., /usr/ast/. ==> /usr/ast). */
  70.   while (1) {
  71.     n = strlen(dirname);
  72.     if (n > 2 && dirname[n-2] == '/' && dirname[n-1] == '.') 
  73.         dirname[n-2] = 0;
  74.     else
  75.         break;
  76.   }
  77.   
  78.   /* Are we trying to remove "." or ".." ? */
  79.   if (p = strrchr(dirname, '/'))
  80.     p++;
  81.   else
  82.     p = dirname;
  83.   if (strcmp(p, ".") == 0 || strcmp(p, "..") == 0) {
  84.     stderr2(dirname, " will not remove \".\" or \"..\"\n");
  85.     error++;
  86.     return;
  87.   }
  88.  
  89.   /* Write permission in parent directory ? */
  90.   strcpy(dots, dirname);
  91.   while (dirname[fd])
  92.     if (dirname[fd++] == '/') sl = fd;
  93.   dots[sl] = '\0';
  94.   if (*dots == '\0') strcpy(dots, ".");
  95.   if (access(dots, 2)) {
  96.     stderr2(dirname, " no permission\n");
  97.     error++;
  98.     return;
  99.   }
  100.  
  101.   /* Are we trying to remove current directory ? */
  102.   stat(".", &cwd);
  103.   if ((s.st_ino == cwd.st_ino) && (s.st_dev == cwd.st_dev)) {
  104.     std_err("rmdir: can't remove current directory\n");
  105.     error++;
  106.     return;
  107.   }
  108.  
  109.   /* Is it possible to open the directory ? */
  110.   if ((fd = open(dirname, O_RDONLY)) < 0) {
  111.     stderr2("can't read ", dirname);
  112.     std_err("\n");
  113.     error++;
  114.     return;
  115.   }
  116.  
  117.   /* Is the directory empty ? (except "." and "..") */
  118.   while(read(fd, (char *) &d, sizeof(struct direct)) == sizeof(struct direct)){
  119.     if (d.d_ino != 0) {
  120.         if (strcmp(d.d_name, ".") && strcmp(d.d_name, "..")) {
  121.             stderr2(dirname, " not empty\n");
  122.             close(fd);
  123.             error++;
  124.             return;
  125.         }
  126.     }
  127.   }
  128.   close(fd);
  129.  
  130.   /* Will the path name be invalidated when dirname/. or dirname/.. is
  131.    * unlinked ? In that case, fix the path-name ! */
  132.   strcpy(dots, dirname);
  133.   patch_path(dots);
  134.  
  135.   /* OK, let's do the rmdir. */
  136.   if (rmdir(dots) != 0) {
  137.     stderr2("can't remove ", dots);
  138.     std_err("\n");
  139.     error++;
  140.     return;
  141.   }
  142. }
  143.  
  144. stderr2(s1, s2)
  145. char *s1, *s2;
  146. {
  147.   std_err("rmdir: ");
  148.   std_err(s1);
  149.   std_err(s2);
  150. }
  151.  
  152. /* With s pointing to the first char in the next part of the pathname,
  153.  * check if this part is empty (/), dot (./) or dotdot (../)
  154.  */
  155. #define IS_EMPTY(s)  (*(s) == '/')
  156. #define IS_DOT(s)    (*(s) == '.' && *((s)+1) == '/')
  157. #define IS_DOTDOT(s) (*(s) == '.' && *((s)+1) == '.' && *((s)+2) == '/')
  158.  
  159. patch_path(dir)
  160. char *dir;
  161. {
  162. /* Check if the path name will be invalidated when `dirname/..' and
  163.  * `dirname/.' is later unlinked. Return a (possibly) patched path.
  164.  * Do this by cleaning the path up, i.e. removing unnecessary parts
  165.  * of the path. `anypath/anything/../' , `anypath/./' and `anypath//'
  166.  * are all considered equal to `anypath/' . This assumption will break
  167.  * when symbolic links are (are they ?) introduced. Don't remove those
  168.  * `../' parts that are essential to the path name.
  169.  */
  170.  
  171.   register char *p;
  172.   char *last;
  173.   int level = 0;
  174.  
  175.   if (*dir == '/')        /* absolute ? */
  176.     last = dir + 1;
  177.   else
  178.     last = dir;
  179.  
  180.   p = last;
  181.   while (*p != '\0') {        /* clean up the path name */
  182.     if (IS_EMPTY(p)) {    /* reduce `//' to `/' */
  183.         StrCpy(p, p + 1);
  184.         continue;
  185.     }
  186.     if (IS_DOT(p)) {    /* reduce `/./'  to `/' */
  187.         StrCpy(p, p + 2);
  188.         continue;
  189.     }
  190.     if (IS_DOTDOT(p)) {    /* reduce `/anything/../' to `/' */
  191.         if (level > 0) {/* is it possible to reduce? */
  192.             --level;
  193.             StrCpy(last, p + 3);
  194.             p = last;
  195.             last -= 2;
  196.             while (*last != '/' && last > dir) --last;
  197.             if (*last == '/') last++;
  198.         } else
  199.             last = p += 3;
  200.         continue;
  201.     }
  202.     last = p;
  203.     level++;
  204.     while (*p != '\0' && *p++ != '/');    /* get next part of path
  205.                          * name */
  206.   }
  207. }
  208.  
  209. StrCpy(s, t)
  210. register char *s, *t;
  211. {
  212. /* Overlapping copies are implemetation-dependent in strcpy, so we'll
  213.  * use our own version.
  214.  */
  215.  
  216.   while (*s++ = *t++)        /* do nothing */
  217.     ;
  218. }
  219.